package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type Person struct {
	Name string `json:"name" label:"Name is: ""`
	Age  int    `json:"age" label:"Age is: "`
	Addr string `json:"addr,omitempty" label:"Gender is: " default:"unknown"`
}

func main() {
	p1 := Person{
		Name: "Jack",
		Age:  22,
	}

	data1, err := json.Marshal(p1)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", data1)

	p2 := Person{
		Name: "jack",
		Age:  22,
		Addr: "China",
	}

	data2, err := json.Marshal(p2)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s\n", data2)

	name1, _ := reflect.TypeOf(p1).FieldByName("Name")
	age1 := reflect.ValueOf(p1).Type().Field(1)
	addr1 := reflect.ValueOf(&p1).Elem().Type().Field(2)
	fmt.Printf("%s %s %s\n", name1.Tag, age1.Tag, addr1.Tag)

	labelValue1 := name1.Tag.Get("json")
	labelValue2, ok := age1.Tag.Lookup("json")
	fmt.Printf("%s %s %t\n", labelValue1, labelValue2, ok)

	err = Print(p1)
	if err != nil {
		return
	}
}

func Print(obj interface{}) error {
	v := reflect.ValueOf(obj)

	for i := 0; i < v.NumField(); i++ {
		field := v.Type().Field(i)
		tag := field.Tag
		label := tag.Get("label")
		defaultValue := tag.Get("default")

		value := fmt.Sprintf("%v", v.Field(i))
		if value == "" {
			value = defaultValue
		}

		fmt.Println(label + value)
	}

	return nil
}
